package com.icloud.system.boot.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icloud.auth.api.feign.AuthFeignClient;
import com.icloud.auth.api.vo.Oauth2TokenVo;
import com.icloud.common.cache.util.TokenUtil;
import com.icloud.common.core.api.CommonResult;
import com.icloud.common.core.api.ResultCode;
import com.icloud.common.core.constant.AuthConstant;
import com.icloud.common.database.mapper.AppCustomerAuthMapper;
import com.icloud.common.database.mapper.AppCustomerMapper;
import com.icloud.common.database.model.AppCustomer;
import com.icloud.common.database.model.AppCustomerAuth;
import com.icloud.common.web.domain.UserDto;
import com.icloud.common.web.enums.StateEnum;
import com.icloud.common.web.exception.Asserts;
import com.icloud.common.web.util.AuthUtil;
import com.icloud.system.boot.dao.AppCustomerDao;
import com.icloud.system.boot.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
/**
 * 前台客户账号service实现类
 */
@Service
public class AppCustomerAuthServiceImpl extends ServiceImpl<AppCustomerAuthMapper, AppCustomerAuth> implements AppCustomerAuthService {
    @Autowired
    private AppCustomerMapper appCustomerMapper;
    @Autowired
    private AppCustomerDao appCustomerDao;
    @Autowired
    private AuthFeignClient authFeignClient;
    @Autowired
    private AuthUtil authUtil;
    @Autowired
    private TokenUtil tokenUtil;

    /**
     * 前台客户账号登录
     * @param username 用户名
     * @param password 密码
     */
    @Override
    @Transactional
    public CommonResult<Oauth2TokenVo> appCustomerLogin(String username, String password){

        Asserts.fail(StrUtil.isEmpty(username) || StrUtil.isEmpty(password), ResultCode.USERNAME_OR_PASSWORD_CAN_NOT_BE_EMPTY);
        AppCustomer appCustomer = appCustomerMapper.selectOne(new LambdaQueryWrapper<AppCustomer>().eq(AppCustomer::getUsername, username));
        Asserts.fail(null == appCustomer,ResultCode.USERNAME_OR_PASSWORD_ERROR);

        AppCustomerAuth appCustomerAuth = getOne(new LambdaQueryWrapper<AppCustomerAuth>().eq(AppCustomerAuth::getCustomerId, appCustomer.getId()));

        //校验密码
        Asserts.fail(!BCrypt.checkpw(password, appCustomerAuth.getPassword()),ResultCode.USERNAME_OR_PASSWORD_ERROR);

        //检测账号是否启用
        if(appCustomer.getState().equals(StateEnum.STOP.getCode())) {
            Asserts.fail(ResultCode.ACCOUNT_DISABLED);
        }

        //换取token
        Map<String, String> loginParams = new HashMap<>();
        loginParams.put("client_id", AuthConstant.APP_CLIENT_ID);
        loginParams.put("client_secret", AuthConstant.CLIENT_SECRET);
        loginParams.put("grant_type", "password");
        loginParams.put("username", appCustomer.getUsername());
        loginParams.put("password", password);
        CommonResult<Oauth2TokenVo> tokenResult = authFeignClient.getAccessToken(loginParams);
        if (ResultCode.SUCCESS.getCode() == tokenResult.getCode() && tokenResult.getData() != null) {
            // 前端无法解析jwt
            tokenResult.getData().setCustomerId(appCustomer.getId());
        }else{
            // tokenResult = CommonResult.failed(ResultCode.FAILED);
        }
        return tokenResult;
    }

    @Override
    public CommonResult<Boolean> appCustomerLogout() {
        tokenUtil.removeAccessToken(authUtil.getAuthHashKey());
        return CommonResult.success();
    }

    /**
     * 根据username查询用户信息
     * @param username
     * @return
     */
    @Override
    public UserDto loadCustomerByUsername(String username) {
        Asserts.fail(StringUtils.isBlank(username), ResultCode.VALIDATE_FAILED);

        UserDto userDto = appCustomerDao.getUserDto(username);
        //构造数据返回
        userDto.setClientId(AuthConstant.APP_CLIENT_ID);
        return userDto;
    }

    @Override
    public Long findCustomerByMnemonics(String mnemonics) {
        Asserts.fail(StringUtils.isBlank(mnemonics), ResultCode.VALIDATE_FAILED);

        AppCustomerAuth appCustomerAuth = baseMapper.selectOne(new LambdaQueryWrapper<AppCustomerAuth>().eq(AppCustomerAuth::getMnemonics, mnemonics));
        Asserts.fail(null==appCustomerAuth, ResultCode.DATA_NOT_EXISTS);
        return appCustomerAuth.getCustomerId();
    }


    /**
     * 修改账号登录密码
     */
    //@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public boolean updatePasswordById(Long accountId, String newPassword) {
        //获取账号授权信息
        AppCustomerAuth auth = getOne(
                new LambdaQueryWrapper<AppCustomerAuth>()
                        .eq(AppCustomerAuth::getCustomerId, accountId)
        );
        Asserts.fail(null == auth, ResultCode.DATA_NOT_EXISTS);

        auth.setPassword(BCrypt.hashpw(newPassword));

        updateById(auth);

        appCustomerLogout();
        return true;
    }

    @Override
    public boolean resetPasswordById(Long accountId, String mnemonic, String newPassword) {
        //获取账号授权信息
        AppCustomerAuth auth = getOne(
                new LambdaQueryWrapper<AppCustomerAuth>()
                        .eq(AppCustomerAuth::getCustomerId, accountId)
                        .eq(AppCustomerAuth::getMnemonics, mnemonic)
        );
        Asserts.fail(null == auth, ResultCode.DATA_NOT_EXISTS);
        auth.setPassword(BCrypt.hashpw(newPassword));
        updateById(auth);
        return true;
    }

    @Override
    public boolean updateTxPasswordById(Long accountId, String newPassword) {
        //获取账号授权信息
        AppCustomerAuth auth = getOne(
                new LambdaQueryWrapper<AppCustomerAuth>()
                        .eq(AppCustomerAuth::getCustomerId, accountId)
        );
        Asserts.fail(null == auth, ResultCode.DATA_NOT_EXISTS);
        auth.setTxPassword(BCrypt.hashpw(newPassword));
        updateById(auth);
        return true;
    }
}
